package Lib3d.Physics;


import Lib3d.Vector3d;
import Lib3d.SceneGraph.Impl.ObjectNodeImpl;
import main.JavaRenderer;

import java.util.Vector;

import javax.media.opengl.GL;
import javax.media.opengl.GLAutoDrawable;
import javax.media.opengl.glu.GLU;
import javax.media.opengl.glu.GLUquadric;

/**
 * A mass implementation.
 * 
 * @author Wassim Chegham
 * @version 0.1
 * @category Lib3d.Physics
 * 
 */
public class Mass extends ObjectNodeImpl {
    private static final float radius = 1f;
    private final float mass = 50f;
    private final Vector3d force;
    private Vector3d currentLocation;
    private Vector3d previousLocation;
    private Vector3d acceleration;

    public Mass(final Vector3d position) {
        this.currentLocation = position;
        this.previousLocation = position;
        this.force = new Vector3d(0, 0, 0);
        this.acceleration = new Vector3d(0, 0, 0);
    }

    // Newtons second law: a = a + (f/m)
    public Mass applyForce(final Vector3d force) {
        this.acceleration = Vector3d.add(this.acceleration,
                Vector3d.mul(force, 1 / this.mass));
        return this;
    }

    public Mass applyForces(final Vector<Vector3d> f) {
        for (int i = 0; i < f.size(); i++) {
            this.applyForce(f.get(i));
        }
        return this;
    }

    @Override
    public void draw(final GLAutoDrawable gLDrawable) {
        super.draw(gLDrawable);
        final GL gl = gLDrawable.getGL();
        final GLU glu = JavaRenderer.glu;

        gl.glPushMatrix();
        gl.glEnable(GL.GL_COLOR_MATERIAL);

        gl.glTranslatef(this.currentLocation.get(0), this.currentLocation.get(1),
                this.currentLocation.get(2));

        gl.glColor3fv((new Vector3d(1, 0, 0)).toBuffer());
        final GLUquadric sphere = glu.gluNewQuadric();
        glu.gluQuadricDrawStyle(sphere, GLU.GLU_FILL);
        glu.gluQuadricNormals(sphere, GLU.GLU_SMOOTH);
        glu.gluQuadricOrientation(sphere, GLU.GLU_OUTSIDE);
        glu.gluSphere(sphere, Mass.radius, 4, 4);
        glu.gluDeleteQuadric(sphere);

        gl.glDisable(GL.GL_COLOR_MATERIAL);
        gl.glPopMatrix();
    }

    public Vector3d getForce() {
        return this.force;
    }

    public Vector3d getLocation() {
        return this.currentLocation;
    }

    public float getMass() {
        return this.mass;
    }

    public Vector3d getPreviousLocation() {
        return this.previousLocation;
    }

    public Mass setLastLocation(final Vector3d lastLocation) {
        this.previousLocation = lastLocation;
        return this;
    }

    public Mass setLocation(final Vector3d location) {
        this.previousLocation = this.currentLocation;
        this.currentLocation = location;
        return this;
    }

    public Mass setOffsetLocation(final Vector3d correctionVectorHalf) {
        this.previousLocation = this.currentLocation;
        this.currentLocation = Vector3d.add(this.currentLocation, correctionVectorHalf);
        return this;
    }

    public Mass solve(final float dt) {

        // current_p = current_p + (current_p - previous_p)*(1-dampin) +
        // (acceleration*dt)

        final Vector3d tmpLocation = this.currentLocation;
        final Vector3d velocity = Vector3d.sub(this.currentLocation,
                this.previousLocation);
        final Vector3d dampingVelocity = Vector3d.mul(velocity,
                1 - Spring.getSpringDampingFactor());
        final Vector3d dxa = Vector3d.add(dampingVelocity,
                Vector3d.mul(this.acceleration, dt));
        this.currentLocation = Vector3d.add(this.currentLocation, dxa);
        this.previousLocation = tmpLocation;

        this.acceleration = new Vector3d(0, 0, 0);
        return this;
    }

    @Override
    public String toString() {
        return "Mass: " + this.currentLocation.toString();
    }
}
